package cn.itsource.service.impi;

import cn.itsource.doc.CourseDoc;
import cn.itsource.dto.CourseQueryDto;
import cn.itsource.mapper.HighlightResultMapper;
import cn.itsource.repo.CourseElasticsearchRepository;
import cn.itsource.result.PageList;
import cn.itsource.service.EsService;
import cn.itsource.vo.AggTermsVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class EsServiceImpl implements EsService {
    @Autowired
    private CourseElasticsearchRepository repo;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;
    @Override
    public PageList searchCourse(CourseQueryDto dto) {
        //课程高级查询从ES中
            //本地查询构造器
            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

            /***********************************************************************************
             * 设置查询条件
             ***********************************************************************************/
            //分页要用本地查询器
            queryBuilder.withPageable(PageRequest.of(dto.getPage()-1,dto.getRows()));
            //排序
            if(StringUtils.hasLength(dto.getSortField())){
                //默认降序
                SortOrder order= SortOrder.DESC;
                String orderString= StringUtils.hasLength(dto.getSortType())?dto.getSortType():"desc";
                if(orderString.equals("asc")){
                    order=SortOrder.ASC;
                }
                queryBuilder.withSort(SortBuilders.fieldSort(dto.getSortField()).order(order));
            }
            /**
            *author 枫落尘
             * 组合查询器,es中将查询分了2个类型
             * 1.like 模糊查询 查询
             * 2.= 精确查找 过滤
            */
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            //过滤
            if(dto.getCourseTypeId()!=null){
                boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId",dto.getCourseTypeId()));
            }
        /**
         term：不会将查询条件分词
         match:会将查询条件进行分词，然后进行匹配
         */
            if(StringUtils.hasLength(dto.getKeyword())){
                boolQueryBuilder.must(QueryBuilders.matchQuery("name",dto.getKeyword()));
            }
            if(dto.getPriceMin()!=null){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
            }
            if(dto.getPriceMax() != null){
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
            }
        //查询

            /***********************************************************************************
             ***********************************************************************************/

            //将组合查询器放入本地查询器中，进行关联
            queryBuilder.withQuery(boolQueryBuilder);

            //关键字高亮
            HighlightBuilder.Field field1 = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
            HighlightBuilder.Field field2 = new HighlightBuilder.Field("tenantName").preTags("<font style='color:red'><b>").postTags("</b></font>");

            queryBuilder.withHighlightFields(field1, field2);
            //  Page<CourseDoc> page = repo.search(queryBuilder.build());

            //聚合查询
            TermsAggregationBuilder termsAggregationBuilder1 = AggregationBuilders.terms("gradeAggs").field("gradeName").order(Terms.Order.count(false)).size(10);
            TermsAggregationBuilder termsAggregationBuilder2 = AggregationBuilders.terms("tenantAggs").field("tenantName").order(Terms.Order.count(false)).size(10);
            queryBuilder.addAggregation(termsAggregationBuilder1).addAggregation(termsAggregationBuilder2);

            //执行查询
            AggregatedPage<CourseDoc> page = elasticsearchTemplate.queryForPage(queryBuilder.build(), CourseDoc.class, highlightResultMapper);

            Map<String, List<AggTermsVo>> aggrMap = new HashMap<>();

            Map<String, Aggregation> stringAggregationMap = page.getAggregations().asMap();
            Set<Map.Entry<String, Aggregation>> entries = stringAggregationMap.entrySet();
            entries.forEach(e -> {
                List<AggTermsVo> list = new ArrayList<>();
                String key = e.getKey();
                StringTerms value = (StringTerms) e.getValue();
                //取出聚合计算结果
                List<StringTerms.Bucket> buckets = value.getBuckets();
                AggTermsVo dto2 = null;
                for(int i = 0; i<buckets.size(); i++){
                    dto2 = new AggTermsVo();
                    StringTerms.Bucket bucket = buckets.get(i);
                    String keyAsString = bucket.getKeyAsString();
                    long docCount = bucket.getDocCount();

                    dto2.setKey(keyAsString);
                    dto2.setDocCount(docCount);
                    list.add(dto2);
                }
                aggrMap.put(key, list);
            });
            //将结果封装返回
            return new PageList<CourseDoc>(page.getTotalElements(), page.getContent(), aggrMap);
        }
}
